Spring MVC
内容 | 说明 | 重要程度 |
---|---|---|
Spring MVC入门 | Spring MVC开发流程与环境配置 | ★★★★★★ |
接收Web数据 | Spring MVC参数接收与数据绑定 | ★★★★★★ |
URL Mapping | 讲解URL绑定过程 | ★★★★★★ |
中文乱码问题 | 解决请求与相应中文乱码 | ★★★★★★ |
拦截器 | Spring MVC拦截器的使用 | ★★★ |
Restful开发风格 [主流]
内容 | 说明 | 重要程度 |
---|---|---|
Restful风格介绍 | 介绍Restful开发规范 | ★★★★★★ |
Restful开发实战 | 实例讲解Restful在Spring MVC中的实现 | ★★★★★★ |
JSON序列化 | 通过相应输出数据 | ★★★★★★ |
Restful的跨域问题 | 分析跨域问题的来源与解决办法 | ★★★★★★ |
Spring MVC[Model+View+Controller(中介)]
比servlet方便许多 简化web程序的开发
- Spring MVC是Spring体系的轻量级Web MVC框架
- Spring MVC的核心Controller控制器,用于处理请求,产生相应
- Spring MVC基于Spring IOC容器运行,所有对象被IoC管理
学习向导
- Spring MVC入门
- Spring MVC数据绑定
- Restful 开发风格
- Spring MVC拦截器
Spring MVC环境配置
IDEA环境下创建Maven WebApp
Project Structure 点加号 添加Web 右侧Path是Web描述符所存储的路径C:\Users\Pluminary\Desktop\SpringMVC\src\main\webapp\WEB-INF\web.xml
Deployment descriptor version => 3.1
下面的 Web Resource Directory【用于目录存储页面】C:\Users\Pluminary\Desktop\SpringMVC\src\main\webapp
再次点下方的Create Artifact
右上角Type:
Web Application: Exploded 目录方式运行
Web Application: Archive 打包成war包运行
配置Tomcat Server => Deployment 添加当前工程 SpringMVC:Web exploded
下面的Application context: 设置为 / 只访问localhost即可
Server选项框里的 On ‘Update’ action: 把Restart server 改成 Update classes and resources【热部署】
当页面源代码发生变化时 不需要重启
- Maven依赖Spring-WebMVC
- web.xml配置DispatcherServlet
- 配置applicationContext的mvc标记
- 开发Controller控制器
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.imooc</groupId>
<artifactId>first-springmvc</artifactId>
<version>1.0-SNAPSHOT</version>
<repositories>
<repository>
<id>aliyun</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
</dependencies>
</project>
src/main/webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- DispatchServlet 对所有请求进行拦截 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<!-- DispatcherServlet是Spring MVC是最核心的对象
DispatcherServlet用于拦截http请求
并根据请求的URL调用与之对应的Controller方法,来完成Http请求的处理
-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 在Web应用启动时自动创建Spring IoC容器,并初始化DispatcherServlet -->
<!-- applicationContext.xml 初始化参数 启动时候加载-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- "/" 所有请求都要拦截-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- context:component-scan标签作用 在Spring IoC初始化过程中, 自动创建并管理com.imooc.springmvc
及子包中拥有以下注解的对象:
@Repository 通常存放在Dao类上 通常都是与数据发生直接交互的类
@Service ...Service类上 业务逻辑类
@Controller 描述SpringMVC的控制器类
@Component 无法确定的类型种类
-->
<context:component-scan base-package="com.imooc.springmvc"></context:component-scan>
<!-- 启用Spring MVC的注解开发模式-->
<mvc:annotation-driven/>
<!-- 将图片/JS/CSS等静态资源排除在外, 可提高执行效率-->
<mvc:default-servlet-handler/>
</beans>
com/imooc/springmvc/controller/TestController.java
package com.imooc.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestController {
// 将当前的方法绑定某个get方式请求的url //localhost/t
@GetMapping("/t")
// 直接向响应输出字符串数据,不跳转页面
@ResponseBody
public String test(){
return "SUCCESS";
}
}
添加依赖jar包进入项目工程 配置tomcat服务Run/Debug Configurations
中的 Deployment
点一下小铅笔修改 将右侧的Avaliable Elements中的依赖包全部put进入404bug 配置都正常无误 寻找一下项目工程里的out/artifacts/WEB-INF/web.xml
Spring MVC数据绑定
URL Mapping(URL映射)
- URL Mapping指将URL与Controller方法绑定
- 通过将URL与方法绑定,SpringMVC便可通过Tomcat对外暴露服务
URL Mapping注解
- @RequestMapping - 通用绑定 //在全局用则是通用请求映射访问前缀 若在方法上则不区分get/post请求
- @GetMapping - 绑定Get请求
- @PostMapping - 绑定Post请求
@GetMapping("/g") ====== @RequestMapping(value="/g",method=RequestMethod.GET)
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.imooc</groupId>
<artifactId>first-springmvc</artifactId>
<version>1.0-SNAPSHOT</version>
<repositories>
<repository>
<id>aliyun</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
</project>
src/main/webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- DispatchServlet 对所有请求进行拦截 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<!-- DispatcherServlet是Spring MVC是最核心的对象
DispatcherServlet用于拦截http请求
并根据请求的URL调用与之对应的Controller方法,来完成Http请求的处理
-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 在Web应用启动时自动创建Spring IoC容器,并初始化DispatcherServlet -->
<!-- applicationContext.xml 初始化参数 启动时候加载-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- "/" 所有请求都要拦截-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- context:component-scan标签作用 在Spring IoC初始化过程中, 自动创建并管理com.imooc.springmvc
及子包中拥有以下注解的对象:
@Repository 通常存放在Dao类上 通常都是与数据发生直接交互的类
@Service ...Service类上 业务逻辑类
@Controller 描述SpringMVC的控制器类
@Component 无法确定的类型种类
-->
<context:component-scan base-package="com.imooc.springmvc"></context:component-scan>
<!-- 启用Spring MVC的注解开发模式-->
<mvc:annotation-driven/>
<!-- 将图片/JS/CSS等静态资源排除在外, 可提高执行效率-->
<mvc:default-servlet-handler/>
</beans>
com/imooc/springmvc/controller/TestController.java
package com.imooc.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestController {
@GetMapping("/t") //localhost/t
@ResponseBody //直接向响应输出字符串数据,不跳转页面
public String test(){
return "Hello Spring MVC";
}
}
com/imooc/springmvc/controller/URLMappingController.java
package com.imooc.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping ("/um") //类上直接使用默认访问前缀 全局通用请求映射
public class URLMappingController {
@GetMapping("/g")
@ResponseBody
public String getMapping(){
return "This is get method";
}
// 直接访问会出错 post请求如何访问 用进行html表单提交
@PostMapping("/p")
@ResponseBody
public String postMapping(){
return "This is post method";
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/um/p" method="post">
<input type="submit" value="提交">
</form>
</body>
</html>
Controller方法参数接收请求参数
接收请求参数的常用做法
<form action="/m1" method="post">
<input name="username"/>
<input name="password"/>
</form>
----------------------------------------------------
@PostMapping("/m1")
@ResponseBody
public String post(String username, Long password){
return username + ":" + password;
}
特殊的注解@RequestParam("")
接收特殊自定义的参数
com/imooc/springmvc/controller/URLMappingController.java
package com.imooc.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/um") //类上直接使用默认访问前缀 全局通用请求映射
public class URLMappingController {
@GetMapping("/g")
@ResponseBody
public String getMapping(@RequestParam("manager_name") String managerName) {
System.out.println("managerName:"+managerName);
return "This is get method";
}
// 直接访问会出错 post请求如何访问 用进行html表单提交
@PostMapping("/p")
@ResponseBody
public String postMapping(String username, String password) {
System.out.println(username + ":" + password);
return "This is post method";
}
}
=========================
网页中输入 http://localhost/um/g?manager_name=lily
控制台返回 managerName:lily
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/um/p" method="post">
<input name="username"><br/>
<input name="password"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/um/p1" method="post">
<input name="username"><br/>
<input name="password"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
用实体对象User
进行接收多个对象的创建和注入以及类型转换 [一次性完成]
com/imooc/springmvc/controller/URLMappingController.java
@PostMapping("/p1")
@ResponseBody //只要拥有User属性和参数 就可以一起赋值
public String postMapping1(User user, String username){
System.out.println(user.getUsername() + ":" + user.getPassword());
return "This is post method";
}
User.java
//标准的java bean
public class User {
private String username;
private Long password;
} Setter + Getter
踩坑记录:IDEA web项目out artifacts文件夹只包含WEB-INF_out artifacts无法生成test.html-CSDN博客
综合训练:学员调查问卷
知识点
- 利用数组或者List接收请求中的复合数据
- 利用@RequestParam为参数设置默认值
- 使用Map对象接收请求参数及注意事项
URI绝对路径与相对路径
相对地址的应用案例
<form action="./apply" method="post"
- 页面地址:http://localhost:8080/[上下文路径]/form.html
- 提交地址:http://localhost:8080/[上下文路径]/apply
src/main/webapp/form.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>学员调查问卷</title>
<style>
.container {
position: absolute;
border: 1px solid #cccccc;
left: 50%;
top: 50%;
width: 400px;
height: 300px;
margin-left: -200px;
margin-top: -150px;
box-sizing: border-box;
padding: 10px;
}
h2{
margin: 10px 0px;
text-align: center;
}
h3{
margin: 10px 0px;
}
</style>
</head>
<body>
<div class="container">
<h2>学员调查问卷</h2>
<form action="./apply" method="post">
<h3>您的姓名</h3>
<input name="name" class="text" style="width: 150px">
<h3>您正在学习的技术方向</h3>
<select name="course" style="width: 150px">
<option value="java">Java</option>
<option value="h5">HTML5</option>
<option value="python">Python</option>
<option value="php">PHP</option>
</select>
<div>
<!--复选框用数组 或 ArrayList接收-->
<h3>您的学习目的:</h3>
<input type="checkbox" name="purpose" value="1">就业找工作
<input type="checkbox" name="purpose" value="2">工作要求
<input type="checkbox" name="purpose" value="3">兴趣爱好
<input type="checkbox" name="purpose" value="4">其他
</div>
<div style="text-align: center;padding-top:10px" >
<input type="submit" value="提交" style="width:100px">
</div>
</form>
</div>
</body>
</html>
如果要接收复合数据 直接用数组接收是最简单的 但使用起来并不轻松
可以使用List来接收 但是前方记得要有@RequestParam
更加高级的可以封装成一个对象 用List接收复合数据
Map只能接收单个数据 接收复合数据的时候会造成数据丢失
com/imooc/springmvc/controller/FormController.java
package com.imooc.springmvc.controller;
import com.imooc.springmvc.entity.Form;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.Map;
@Controller
public class FormController {
// @PostMapping("/apply") ★★★第一次尝试★★★
@ResponseBody
// 如果在请求中不包含默认值 => 取别名 默认值机制:ANON匿名
public String apply(@RequestParam(value = "n", defaultValue = "ANON") String name, String course, Integer[] purpose){
System.out.println(name);
System.out.println(course);
for (Integer p:purpose){
System.out.println(p);
}
return "SUCCESS";
}
// @PostMapping("/apply") ★★★第二次尝试★★★
// 请求中的复合数据要被转换为List进行存储
@ResponseBody
public String apply(String name, String course, @RequestParam List<Integer> purpose){
System.out.println(name);
System.out.println(course);
for (Integer p:purpose){
System.out.println(p);
}
return "SUCCESS";
}
@PostMapping("/apply")
//★★★★★ 推荐使用 ★★★★★
// 实体类+List 极大简化表单工作量
// 请求中的复合数据要被转换为List进行存储
@ResponseBody
public String apply(Form form){
return "SUCCESS";
}
//不推荐直接使用Map导入数据 因为复合数据[数组数据]会丢失
}
com/imooc/springmvc/entity/Form.java
public class Form {
private String name;
private String course;
private List<Integer> purpose;
}Setter + Getter
关联对象赋值
复杂内容表单
用户名: <input name="username">
密码:<input name="password">
--------------------------------
姓名:<input name="name">
身份证号:<input name="idno">
过期时间:<input name="expire">
面向对象设计 【关联对象赋值】
public class User{
private String username;
private String password;
private IDcard idcard = new IDCard();
//Getter + Setter
}
★★ 关联上IDcard ★★
public class IDcard{
private String name;
private String idno;
private Date expire;
//Getter + Setter
}
用户名: <input name="username">
密码:<input name="password">
--------------------------------
姓名:<input name="idcard.name">
身份证号:<input name="idcard.idno">
过期时间:<input name="idcard.expire">
src/main/webapp/form.html
<div>
<h3>您的学习目的:</h3>
<input type="checkbox" name="purpose" value="1">就业找工作
<input type="checkbox" name="purpose" value="2">工作要求
<input type="checkbox" name="purpose" value="3">兴趣爱好
<input type="checkbox" name="purpose" value="4">其他
</div>
<h3>收货人</h3>
<!-- private Delivery delivery = new Delivery() -->
<input name="delivery.name" class="text" style="width: 150px">
<h3>联系电话</h3>
<input name="delivery.mobile" class="text" style="width: 150px">
<h3>收货地址</h3>
<input name="delivery.address" class="text" style="width: 150px">
<div style="text-align: center;padding-top:10px" >
<input type="submit" value="提交" style="width:100px">
</div>
com/imooc/springmvc/entity/Form.java
public class Form {
private String name;
private String course;
private List<Integer> purpose;
private Delivery delivery = new Delivery();
} Getter + Setter
com/imooc/springmvc/entity/Delivery.java
public class Delivery {
private String name;
private String address;
private String mobile;
} Getter + Setter
com/imooc/springmvc/controller/FormController.java
package com.imooc.springmvc.controller;
import com.imooc.springmvc.entity.Form;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.Map;
@Controller
public class FormController {
// @PostMapping("/apply") 第一次尝试
@ResponseBody
// 如果在请求中不包含默认值 => 取别名 默认值机制:ANON匿名
public String apply(@RequestParam(value = "n", defaultValue = "ANON") String name, String course, Integer[] purpose){
System.out.println(name);
System.out.println(course);
for (Integer p:purpose){
System.out.println(p);
}
return "SUCCESS";
}
// @PostMapping("/apply") 第二次尝试
// 请求中的复合数据要被转换为List进行存储
@ResponseBody
public String apply(String name, String course, @RequestParam List<Integer> purpose){
System.out.println(name);
System.out.println(course);
for (Integer p:purpose){
System.out.println(p);
}
return "SUCCESS";
}
// @PostMapping("/apply") 第三次尝试[这个可以 但有更好]
// 实体类+List 极大简化表单工作量
// 请求中的复合数据要被转换为List进行存储
@ResponseBody
public String apply(Form form){
return "SUCCESS";
}
@PostMapping("/apply")
@ResponseBody
public String applyDelivery(Form form){
System.out.println(form.getDelivery().getName());
return "SUCCESS";
}
}
日期类型转换
①注解方法
com/imooc/springmvc/controller/URLMappingController.java
@Controller
@RequestMapping("/um") //类上直接使用默认访问前缀 全局通用请求映射
public class URLMappingController {
@PostMapping("/p1")
@ResponseBody
public String postMapping1(User user, String username, @DateTimeFormat(pattern = "yyyy-MM-dd") Date createTime){
System.out.println(user.getUsername() + ":" + user.getPassword());
return "This is post method";
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/um/p1" method="post">
<input name="username"><br/>
<input name="password"><br/>
<input name="createTime"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
②实体对象接收数据
com/imooc/springmvc/entity/User.java
//标准的java bean
public class User {
private String username;
private Long password;
// SpringMVC会自动按照这个类型进行转换
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date createTime;
} Getter + Setter
③自定义转换器:全局的默认时间转换器
com/imooc/springmvc/converter/MyDateConverter.java
package com.imooc.springmvc.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyDateConverter implements Converter<String, Date> {
public Date convert(String s) { //转换工作
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date d = sdf.parse(s);
return d;
} catch (ParseException e) {
return null;
}
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- context:component-scan标签作用 在Spring IoC初始化过程中, 自动创建并管理com.imooc.springmvc
及子包中拥有以下注解的对象:
@Repository 通常存放在Dao类上 通常都是与数据发生直接交互的类
@Service ...Service类上 业务逻辑类
@Controller 描述SpringMVC的控制器类
@Component 无法确定的类型种类
-->
<context:component-scan base-package="com.imooc.springmvc"></context:component-scan>
<!-- 启用Spring MVC的注解开发模式 让底下的转换类生效-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 将图片/JS/CSS等静态资源排除在外, 可提高执行效率-->
<mvc:default-servlet-handler/>
<!-- 通知SpringMVC有哪些转换类-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 这是转换类定义的地方-->
<property name="converters">
<set>
<bean class="com.imooc.springmvc.converter.MyDateConverter"/>
</set>
</property>
</bean>
</beans>
解决中文乱码问题
Web应用的中文乱码由来
- Tomcat默认使用字符集ISO-8859-1,属于西欧字符集
- 解决乱码的核心思路是将ISO-8859-1转换为UTF-8
- Controller中请求与响应都需要设置UTF-8字符集
中文乱码的配置
- Get请求乱码 - server.xml增加URIEncoding属性
去Tomcat-conf文件中寻找server.xml进行增加
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"
maxParameterCount="1000"
/>
===============================================
http://localhost/um/g?manager_name=丽丽
控制台:managerName:丽丽
- Post请求乱码 - web.xml配置CharacterEncodingFilter
http://localhost/
输入:
张三 123456 2001-03-02
随后点击提交
控制台:??????:123456
src/main/webapp/WEB-INF/web.xml
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
http://localhost/
输入:
张三 123456 2001-03-02
随后点击提交
控制台:张三:123456
- Response相应乱码 - Spring配置StringHttpMessageConverter
解决响应中的中文乱码
com/imooc/springmvc/controller/URLMappingController.java
package com.imooc.springmvc.controller;
import com.imooc.springmvc.entity.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
@Controller
@RequestMapping("/um") //类上直接使用默认访问前缀 全局通用请求映射
public class URLMappingController {
@GetMapping("/g")
@ResponseBody
public String getMapping(@RequestParam("manager_name") String managerName) {
System.out.println("managerName:"+managerName);
return "This is get method";
}
// 直接访问会出错 post请求如何访问 用进行html表单提交
@PostMapping("/p")
@ResponseBody
public String postMapping(String username, Long password) {
System.out.println(username + ":" + password);
return "This is post method";
}
// @PostMapping("/p1")
@ResponseBody
public String postMapping1(User user){
System.out.println(user.getUsername() + ":" + user.getPassword());
return "This is post method";
}
@PostMapping("/p1")
@ResponseBody
public String postMapping1(User user, String username, @DateTimeFormat(pattern = "yyyy-MM-dd") Date createTime){
System.out.println(user.getUsername() + ":" + user.getPassword());
return "这是Post响应";
}
}
User.java
//标准的java bean
public class User {
private String username;
private Long password;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date createTime;
}Getter + Setter
com/imooc/springmvc/converter/MyDateConverter.java
package com.imooc.springmvc.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyDateConverter implements Converter<String, Date> {
public Date convert(String s) { //转换工作
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date d = sdf.parse(s);
return d;
} catch (ParseException e) {
return null;
}
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/um/p1" method="post">
<input name="username"><br/>
<input name="password"><br/>
<input name="createTime"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- context:component-scan标签作用 在Spring IoC初始化过程中, 自动创建并管理com.imooc.springmvc
及子包中拥有以下注解的对象:
@Repository 通常存放在Dao类上 通常都是与数据发生直接交互的类
@Service ...Service类上 业务逻辑类
@Controller 描述SpringMVC的控制器类
@Component 无法确定的类型种类
-->
<context:component-scan base-package="com.imooc.springmvc"></context:component-scan>
<!-- 启用Spring MVC的注解开发模式 让底下的转换类生效-->
<mvc:annotation-driven conversion-service="conversionService">
<!-- 设置消息转换器-->
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<!-- 转换什么呢?-->
<property name="supportedMediaTypes">
<list>
<!-- 在servlet中是直接 response.setContentType("text/html;charset=utf-8") -->
<value>text/html;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 将图片/JS/CSS等静态资源排除在外, 可提高执行效率-->
<mvc:default-servlet-handler/>
<!-- 通知SpringMVC有哪些转换类-->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 这是转换类定义的地方-->
<property name="converters">
<set>
<bean class="com.imooc.springmvc.converter.MyDateConverter"/>
</set>
</property>
</bean>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- DispatchServlet 对所有请求进行拦截 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<!-- DispatcherServlet是Spring MVC是最核心的对象
DispatcherServlet用于拦截http请求
并根据请求的URL调用与之对应的Controller方法,来完成Http请求的处理
-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 在Web应用启动时自动创建Spring IoC容器,并初始化DispatcherServlet -->
<!-- applicationContext.xml 初始化参数 启动时候加载-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- "/" 所有请求都要拦截-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
响应中产生结果 [ModelAndView => MVC高效解耦理念]
@ResponseBody - 产生响应文本
- @ResponseBody直接产生响应体数据, 过程不涉及任何视图
- @ResponseBody可产生标准字符串/JSON/XML等格式数据
- @ResponseBody被StringHttpMessageConverter所影响
ModelAndView - 利用模板引擎渲染输出
- ModelAndView对象是指”模型(数据)与视图(界面)”对象
- 通过ModelAndView可将包含数据对象与模板引擎进行绑定
- SpringMVC中默认的View是JSP, 也可以配置其他模板引擎
提问:为什么不直接访问view.jsp 而是绕了一个圈子还是同样的效果
回答:因为jsp页面是写死的如何将页面和数据绑定在一起呢?先通过访问/um/view这个controller让其方法中产生数据, 之后再将这个数据通过modelandview对象绑定到页面中才可以做到从请求传来一个用户编号把数据查询出来得到一个user用户对象 然后再view.jsp中把刚刚查询的对象进行显示[动态的]
高效解耦
后端:com/imooc/springmvc/controller/URLMappingController.java
// http://localhost/um/view?userId=1 数据动态查询产生
@GetMapping("/view")
public ModelAndView showView(Integer userId){
ModelAndView mav = new ModelAndView("/view.jsp");
User user = new User();
if (userId == 1){
user.setUsername("lily");
}else if (userId == 2){
user.setUsername("smith");
}
// 在当前请求中增加一个对象 数据绑定view.jsp
mav.addObject("u", user);
return mav;
}
前端:src/main/webapp/view.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>I'm view page</h1>
<hr>
<h2>Username:${u.username}</h2>
</body>
</html>
ModelAndView [重定向]
[SpringMVC若跳转页面需要使用此对象进行数据绑定]
- mav.addObject()方法设置的属性默认存放在当前请求中
- 默认ModelAndView使用请求转发(forward)至页面
- 重定向使用 new ModelAndView(“redirect:/index.jsp”) 新请求
页面重定向使用时机:内部的controller处理逻辑和跳转页面之间没有直接关系时可以用”redirect:/view.jsp”
ModelAndView mav = new ModelAndView("redirect:/view.jsp");
直接访问到了jsp http://localhost/view.jsp
访问:http://localhost/um/view?userId=1
建立一个 没有斜杠的相对路径 src/main/webapp/um/view.jsp
com/imooc/springmvc/controller/URLMappingController.java
// http://localhost/um/view?userId=1 数据动态查询产生
@GetMapping("/view")
public ModelAndView showView(Integer userId){
// ModelAndView mav = new ModelAndView("redirect:/view.jsp");
ModelAndView mav = new ModelAndView();
mav.setViewName("view.jsp");
// 没有斜杠是代表相对路径 相对于@RequestMapping("/um")地址
// mav.setViewName("view.jsp");
User user = new User();
if (userId == 1){
user.setUsername("lily");
}else if (userId == 2){
user.setUsername("smith");
}
// 在当前请求中增加一个对象 数据绑定view.jsp
mav.addObject("u", user);
return mav;
}
String与ModelMap实现ModelAndView类似功能 [工作中的小技巧]
com/imooc/springmvc/controller/URLMappingController.java
// String 与 ModelMap[为模型数据] 返回字符串
// Controller方法返回String的情况
// 1.方法被@ResponseBody描述, 则SpringMVC直接响应Spring字符串本身
// 2.方法不存在@ResponseBody, 则SpringMVC处理String指代的视图(页面)
// 这里的String是直接代替了@ResponseBody - 产生响应文本
public String showView1(Integer userId, ModelMap modelMap){
String view = "/um/view.jsp";
User user = new User();
if (userId == 1){
user.setUsername("lily");
}else if (userId == 2){
user.setUsername("smith");
}
modelMap.addAttribute("u", user);
return view;
}
SpringMVC整合Freemarker [项目:first-springmvc]
① pom.xml引入依赖
要随时导入包 tomcat → Edit configuration → Deployment → Artifacts 将右侧包put in
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
② 启用Freemarker模板引擎
applicationContext.xml
<bean id="ViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<!-- 设置响应输出,并解决中文乱码 -->
<!-- 渲染完成后向客户端浏览器响应式 响应体中使用的字符集编码 -->
<property name="contentType" value="text/html;charset=utf-8"></property>
<!-- 指定Freemarker模板文件扩展名 -->
<property name="suffix" value=".ftl"/>
</bean>
③ 本身配置Freemarker参数
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<!-- 设置模板保存的目录 tomcat无法直接解析freemarker模板引擎 所以新增/WEB-INF/ftl -->
<property name="templateLoaderPath" value="/WEB-INF/ftl"/>
<!-- 其他模板引擎设置 -->
<property name="freemarkerSettings">
<props>
<!-- 设置Freemarker脚本与数据渲染时使用的字符集 -->
<!-- 模板与数据绑定渲染的过程中使用的字符集编码 -->
<prop key="defaultEncoding">UTF-8</prop>
</props>
</property>
</bean>
src/main/webapp/WEB-INF/ftl/test.ftl
<h1>${u.username}</h1>
com/imooc/springmvc/controller/FreemarkerController.java
package com.imooc.springmvc.controller;
import com.imooc.springmvc.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
// http://localhost/fm/test 显示 andy
@Controller
@RequestMapping("/fm")
public class FreemarkerController {
@GetMapping("/test")
public ModelAndView showTest(){
// 因为之前配置所有配置扩展名是.ftl 所以下面不用写
ModelAndView mav = new ModelAndView("/test");
User user = new User();
user.setUsername("andy");
mav.addObject("u",user);
return mav;
}
}
=====================================================
// http://localhost/fm/test 显示 andy
RESTful开发风格
RESTful 风格(详细介绍 + 案例实现)_c# restful风格接口-CSDN博客
REST与RESTful
- REST- 表现层状态转换, 资源在网络中以某种表现形式进行状态转移
- RESTful是基于REST理念的一套开发风格, 是具体的开发规则
RESTful开发规范
URL中所有的都是名词 请求都有不同的含义 返回的数据是JSON或者XML格式
- 使用URL作为用户交互入口
- 明确的语义规范(GET, POST, PUT, DELETE)
- 只返回数据(JSON, XML)不包含任何展现

注解 | 作用 |
---|---|
@RestController | 由 @Controller + @ResponseBody组成(返回 JSON 数据格式) |
@PathVariable | URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到控制器处理方法的形参中 |
@RequestMapping | 注解用于请求地址的解析,是最常用的一种注解 |
@GetMapping | 查询请求 |
@PostMapping | 添加请求 |
@PutMapping | 更新请求 |
@DeleteMapping | 删除请求 |
@RequestParam | 将请求参数绑定到你控制器的方法参数上(是springmvc中接收普通参数的注解) |
RESTful命名要求
URI | 说明 | 修改建议 |
---|---|---|
GET /articles?au=lily | 正确用法 | |
GET /a/1 | URI必须具有语义 | GET /student/1 |
POST /createArticle/1 | URI必须使用名词 | POST /article/1 |
GET /articles/author/1 | URI扁平化, 不超两级 | GET /articles/author?id=1 |
DELETE/articles/1 | URI名词区分单复数 | GET /articles?au=lily DELETE /article/1 |

开发第一个RESTful应用
404究极报错
项目生成文件out/artifacts/XXX/WEB-INF中没有导入lib包
没有将下面的web文件里的web.xml手动复制进去
pom.xml
写完pom.xml后记得在tomcat配置中的Deployment中加入依赖包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.imooc</groupId>
<artifactId>restful</artifactId>
<version>1.0-SNAPSHOT</version>
<repositories>
<repository>
<id>aliyun</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</project>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.imooc.restful"/>
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<!-- response.setContentType("text/html;charset=utf-8") -->
<value>text/html;charset=utf-8</value>
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:default-servlet-handler/>
</beans>
web/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
com/imooc/restful/controller/RestfulController.java
package com.imooc.restful.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/restful")
public class RestfulController {
@GetMapping("/request")
@ResponseBody
public String doGetRequest(){
// 双引号中如果包括双引号 要用转义字符 \"
return "{\"message\":\"返回查询结果\"}";
}
}
=======================================================
http://localhost/restful/request
{"message":"返回查询结果"}
实现RESTful实验室
com/imooc/restful/controller/RestfulController.java
package com.imooc.restful.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/restful")
public class RestfulController {
@GetMapping("/request")
@ResponseBody
public String doGetRequest(){
// 双引号中如果包括双引号 要用转义字符 \"
return "{\"message\":\"返回查询结果\"}";
}
@PostMapping("/request")
@ResponseBody
public String doPostRequest(){
return "{\"message\":\"数据新建成功\"}";
}
@PutMapping ("/request")
@ResponseBody
public String doPutRequest(){
return "{\"message\":\"数据更新成功\"}";
}
@DeleteMapping("/request")
@ResponseBody
public String doDeleteRequest(){
return "{\"message\":\"数据删除成功\"}";
}
}
===========================
http://localhost/client.html
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.imooc.restful"/>
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<!-- response.setContentType("text/html;charset=utf-8") -->
<value>text/html;charset=utf-8</value>
<!--只要响应产生就会使用utf-8字符集-->
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:default-servlet-handler/>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.imooc</groupId>
<artifactId>restful</artifactId>
<version>1.0-SNAPSHOT</version>
<repositories>
<repository>
<id>aliyun</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.9</version>
</dependency>
</dependencies>
</project>
web/client.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="jquery-3.3.1.min.js"></script>
<script>
$(function () {
$("#btnGet").click(function () {
$.ajax({
url: "/restful/request",
type: "get",
dataType: "json",
success: function (json) {
$("#message").text(json.message);
}
})
});
})
$(function () {
$("#btnPost").click(function () {
$.ajax({
url: "/restful/request",
type: "post",
dataType: "json",
success: function (json) {
$("#message").text(json.message);
}
})
});
})
$(function () {
$("#btnPut").click(function () {
$.ajax({
url: "/restful/request",
type: "put",
dataType: "json",
success: function (json) {
$("#message").text(json.message);
}
})
});
})
$(function () {
$("#btnDelete").click(function () {
$.ajax({
url: "/restful/request",
type: "delete",
dataType: "json",
success: function (json) {
$("#message").text(json.message);
}
})
});
})
</script>
</head>
<body>
<input type="button" id="btnGet" value="发送Get请求">
<input type="button" id="btnPost" value="发送Post请求">
<input type="button" id="btnPut" value="发送Put请求">
<input type="button" id="btnDelete" value="发送Delete请求">
<h1 id="message"></h1>
</body>
</html>
RestController注解与路径变量
在post请求中通过client.html利用Ajax动态注入了一个rid到RestfulController.java
代替了所有的@ResponseBody 默认向请求台进行输出
@Controller: 用于标识一个类是Spring MVC中的控制器,类似于标准的@Controller 注解。它告诉Spring框架该类是一个控制器,可以处理HTTP请求。
@ResponseBody: 用于将方法的返回值直接作为HTTP响应的主体(Body)内容。这意味着不会进行视图解析,而是直接将返回的对象(通常是JSON或XML)写入HTTP响应
因此,@RestController 的作用是将一个控制器类标记为RESTful风格的控制器,其中的每个方法都被视为返回数据,而不是视图。这样就不需要在每个方法上都添加 @ResponseBody 注解,因为该注解已经包含在 @RestController 中。
client.html
$(function(){
$("#btnPost").click(function () {
$.ajax({
url : "/restful/request/100",
type : "post" ,
dataType : "json" ,
success : function(json){
$("#message").text(json.message+":"+json.id);
}
})
});
})
com/imooc/restful/controller/RestfulController.java
package com.imooc.restful.controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/restful")
//@CrossOrigin(origins = {"http://localhost:8080","http://www.imooc.com"})
//@CrossOrigin(origins = "*",maxAge = 3600)
public class RestfulController {
@GetMapping("/request")
//@ResponseBody
public String doGetRequest() {
return "{\"message\":\"返回查询结果\"}";
}
// POST /article/1
// POST /restful/request/100
@PostMapping("/request/{rid}")
//@ResponseBody
public String doPostRequest(@PathVariable("rid") Integer requestId) {
return "{\"message\":\"数据新建成功\",\"id\":" + requestId + "}";
}
@PutMapping("/request")
//@ResponseBody
public String doPutRequest() {
return "{\"message\":\"数据更新成功\"}";
}
@DeleteMapping("/request")
//@ResponseBody
public String doDeleteRequest() {
return "{\"message\":\"数据删除成功\"}";
}
}
简单请求与非简单请求
- 简单请求是指标准结构的HTTP请求, 对应GET/POST请求
- 非简单请求是复杂要求的HTTP请求, 指PUT/DELETE、扩展标准请求
- 两者最大区别是非简单请求发送前需要发送预检请求 [看看能不能进行处理 可以才实际处理 预先处理不符合的数据挡在外面]
web.xml
<!-- 对put和delete请求进行支持-->
<filter>
<filter-name>formContentFilter</filter-name>
<filter-class>org.springframework.web.filter.FormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>formContentFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
web/client.html
$(function(){
$("#btnPost").click(function () {
$.ajax({
url : "/restful/request/100",
type : "post" ,
data : "name=lily&age=23",
dataType : "json" ,
success : function(json){
$("#message").text(json.message+":"+json.id);
}
})
});
})
$(function(){
$("#btnPut").click(function () {
$.ajax({
url : "/restful/request",
type : "put" ,
data : "name=lily&age=23",
dataType : "json" ,
success : function(json){
$("#message").text(json.message);
}
})
});
})
com/imooc/restful/controller/RestfulController.java
// POST /article/1
// POST /restful/request/100
@PostMapping("/request/{rid}")
//@ResponseBody
public String doPostRequest(@PathVariable("rid") Integer requestId, Person person){
System.out.println(person.getName() + ":" + person.getAge());
return "{\"message\":\"数据新建成功\",\"id\":" + requestId + "}";
}
@PutMapping("/request")
//@ResponseBody
public String doPutRequest(Person person){
System.out.println(person.getName() + ":" + person.getAge());
return "{\"message\":\"数据更新成功\"}";
}
====================
lily:23
创建一个Person用来插入数据 并打印在控制台
com/imooc/restful/entity/Person.java
public class Person {
private String name;
private Integer age;
}Getter + Setter
JSON序列化
pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.9</version>
</dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.9</version>
</dependency>
一定要使用2.9以后的版本 之前的版本有严重的安全风险
http://localhost/restful/person?id=1
@GetMapping("/person")
//不返回String 返回JSON序列化的对象
public Person findByPersonId(Integer id){
Person p = new Person();
if (id==1){
p.setName("lily");
p.setAge(23);
} else if (id==2) {
p.setName("smith");
p.setAge(22);
}
return p;
}
============================================
{
"name": "lily",
"age": 23
}
http://localhost/restful/persons
@GetMapping("/persons")
public List<Person> findPersons(){
List list = new ArrayList();
Person p1 = new Person();
p1.setName("lily");
p1.setAge(23);
list.add(p1);
Person p2 = new Person();
p2.setName("smith");
p2.setAge(22);
list.add(p2);
return list;
}
=============================================
[
{
"name": "lily",
"age": 23
},
{
"name": "smith",
"age": 22
}
]
服务器返回json数组
client.html
$(function(){
$("#btnPersons").click(function () {
$.ajax({
url : "/restful/persons",
type : "get" ,
dataType : "json" ,
success : function(json){
console.info(json);
for (var i=0; i<json.length; i++){
var p = json[i];
$("#divPersons").append("<h2>" + p.name + "-" + p.age + "</h2>")
}
}
})
});
})
</script>
</head>
<body>
<input type="button" id="btnGet" value="发送Get请求">
<input type="button" id="btnPost" value="发送Post请求">
<input type="button" id="btnPut" value="发送Put请求">
<input type="button" id="btnDelete" value="发送Delete请求">
<h1 id="message"></h1>
<hr/>
<!-- 点击btnPersons按钮时发送Ajax请求[上面有操作代码] 将所有人员信息追加到div中-->
<input type="button" id="btnPersons" value="查询所有人员">
<div id="divPersons"></div>
</body>
com/imooc/restful/controller/RestfulController.java
@GetMapping("/persons")
public List<Person> findPersons(){
List list = new ArrayList();
Person p1 = new Person();
p1.setName("lily");
p1.setAge(23);
list.add(p1);
Person p2 = new Person();
p2.setName("smith");
p2.setAge(22);
list.add(p2);
return list;
}
===============================================
http://localhost/client.html
点击查询所有人员
=>
lily-23
smith-22
增加时间!
Person.java
public class Person {
private String name;
private Integer age;
// 记得用日期的格式化输出
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date birthday;
}Getter + Setter
client.html
$(function(){
$("#btnPersons").click(function () {
$.ajax({
url : "/restful/persons",
type : "get" ,
dataType : "json" ,
success : function(json){
console.info(json);
for (var i=0; i<json.length; i++){
var p = json[i];
$("#divPersons").append("<h2>" + p.name + "-" + p.age + "-" + p.birthday+ "</h2>")
}
}
})
});
})
===================================
lily-23-2024-01-17 09:09:28
smith-22-2024-01-17 09:09:28
浏览器的同源策略
- 同源策略阻止从一个域加载的脚本去获取另一个域上的资源
- 只要协议、域名、端口有任何一个不同,都被当做是不同的域
- 浏览器Console看到Access-Control-Allow-Origin就代表了跨域了
HTML中允许跨域的标签
- < img > - 显示远程图片
- < script > - 加载远程JS
- < link > - 加载远程CSS
CORS跨域资源访问
- CORS是一种机制, 使用额外的HTTP头通知浏览器可以访问其他域
- URL响应头包含 Access-Control-* 指明请求允许跨域
Spring MVC解决跨域访问
- @CrossOrigin - Controller跨域注解
- < mvc:cors > - Spring MVC全局跨域配置
RestfulController.java [代码第四行]
@RestController
@RequestMapping("/restful")
//@CrossOrigin(origins = {"http://localhost:8080","http://www.imooc.com"})
//@CrossOrigin(origins = "*",maxAge = 3600) 所有端口都会访问发送请求
//maxAge = 3600 一小时时间后发送预检请求 之内的就发送实际请求 【非简单请求】
public class RestfulController {
@GetMapping("/request")
//@ResponseBody
public String doGetRequest(){
return "{\"message\":\"返回查询结果\"}";
}
// POST /article/1
// POST /restful/request/100
@PostMapping("/request/{rid}")
//@ResponseBody
public String doPostRequest(@PathVariable("rid") Integer requestId, Person person){
System.out.println(person.getName() + ":" + person.getAge());
return "{\"message\":\"数据新建成功\",\"id\":" + requestId + "}";
}
@PutMapping("/request")
//@ResponseBody
public String doPutRequest(Person person){
System.out.println(person.getName() + ":" + person.getAge());
return "{\"message\":\"数据更新成功\"}";
}
@DeleteMapping("/request")
//@ResponseBody
public String doDeleteRequest(){
return "{\"message\":\"数据删除成功\"}";
}
@GetMapping("/person")
public Person findByPersonId(Integer id){
Person p = new Person();
if (id==1){
p.setName("lily");
p.setAge(23);
} else if (id==2) {
p.setName("smith");
p.setAge(22);
}
return p;
}
@GetMapping("/persons")
public List<Person> findPersons(){
List list = new ArrayList();
Person p1 = new Person();
p1.setName("lily");
p1.setAge(23);
p1.setBirthday(new Date());
list.add(p1);
Person p2 = new Person();
p2.setName("smith");
p2.setAge(22);
p2.setBirthday(new Date());
list.add(p2);
return list;
}
}
CORS全局配置
<mvc:cors>
<mvc:mapping path="/restful/**"
allowed-origins="http://localhost:8080,http://www.imooc.com"
max-age="3600"/>
</mvc:cors>
SpringMVC拦截器 [高级组件]
拦截器-Interceptor
- 拦截器(Interceptor)用于对URL请求进行前置/后置过滤
- Interceptor与Filter用途相似, 但实现方式不同
- Interceptor底层基于Spring AOP面向切面编程实现[类似于环绕通知]
拦截器开发流程
- Maven依赖servlet-api
- 实现HandlerInterceptor接口
- applicationContext配置过滤地址
HandlerInterceptor接口
- preHandle - 前置执行处理
- postHandle - 目标资源已被Spring MVC框架处理 没产生响应文本
- afterCompletion - 相应文本已经产生
pom.xml
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!-- 只有在开发编译才会引用 打包最终使用的时候会排除在外 因为 servlet-api与tomcat-api冲突 -->
<scope>provided</scope>
</dependency>
</dependencies>
com/imooc/restful/interceptor/MyInterceptor.java
package com.imooc.restful.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
// Code -> Implement Methods
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(request.getRequestURI()+"准备执行");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(request.getRequestURI()+"目标处理成功");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(request.getRequestURI()+"响应内容已产生");
}
// 随后去applicationContext.xml配置
}
=============================================================
/准备执行
/目标处理成功
/响应内容已产生
/准备执行
/目标处理成功
/响应内容已产生
/准备执行
/目标处理成功
/响应内容已产生
http://localhost/restful/persons
/restful/persons准备执行
/restful/persons目标处理成功
/restful/persons响应内容已产生
http://localhost/client.html
/client.html准备执行
/client.html目标处理成功
/client.html响应内容已产生
applicationContext.xml
<mvc:interceptors>
<mvc:interceptor>
<!-- 哪些[所有]地址进行拦截 下面加个bean是哪个类进行处理[送到这个类中处理]-->
<mvc:mapping path="/**"/>
<bean class="com.imooc.restful.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器使用细则
applicationContext.xml
<mvc:interceptors>
<mvc:interceptor>
<!-- 哪些[所有]地址进行拦截 下面加个bean是哪个类进行处理[送到这个java中处理]-->
<!-- <mvc:mapping path="/**"/> -->
<mvc:mapping path="/restful/**"/>
<mvc:mapping path="/webapi/**"/>
<!-- 以下是不需要拦截 排除在外的-->
<mvc:exclude-mapping path="/**.ico"/>
<mvc:exclude-mapping path="/**.jpg"/>
<mvc:exclude-mapping path="/**.gif"/>
<mvc:exclude-mapping path="/**.js"/>
<mvc:exclude-mapping path="/**.css"/>
<!-- 创建一个resources 规范静态文件目录 一次性都排除在外-->
<mvc:exclude-mapping path="/rescources/**"/>
<bean class="com.imooc.restful.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(request.getRequestURI()+"准备执行");
return true;
}
通过preHandle的返回值可以做很多事情
对某一个url进行前置检查 对请求放行 如果不符合要求 直接在拦截器中返回相应
return true; 请求依次向后发送
return false; 请求被阻挡
开发”用户流量”拦截器
pom.xml [引入新的依赖后一定要去Tomcat导入新的依赖包]
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%thread] %d %level %logger{10} - %msg%n</pattern>
</encoder>
</appender>
<appender name="accessHistoryLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>d:/logs/history.%d.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>[%thread] %d %level %logger{10} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="console"/>
</root>
<logger name="com.imooc.restful.interceptor.AccessHistoryInterceptor"
level="INFO" additivity="false">
<appender-ref ref="accessHistoryLog"/>
</logger>
</configuration>
com/imooc/restful/interceptor/AccessHistoryInterceptor.java
package com.imooc.restful.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AccessHistoryInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(AccessHistoryInterceptor.class);
// 前置处理
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
StringBuilder log = new StringBuilder();
log.append(request.getRemoteAddr());
log.append("|");
log.append(request.getRequestURL());
log.append("|");
log.append(request.getHeader("user-agent"));
logger.info(log.toString());
return true;
}
}
com/imooc/restful/interceptor/MyInterceptor.java
package com.imooc.restful.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
// Code -> Implement Methods
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(request.getRequestURL() + "-准备执行");
// response.getWriter().print("[]");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(request.getRequestURL() + "-目标处理成功");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(request.getRequestURL() + "-响应内容已产生");
}
}
==============================================================
http://localhost/client.html
[http-nio-80-exec-1] 2024-01-18 10:43:54,739 DEBUG o.s.w.s.DispatcherServlet - GET "/login.html", parameters={}
[http-nio-80-exec-1] 2024-01-18 10:43:54,750 DEBUG o.s.w.s.h.SimpleUrlHandlerMapping - Mapped to org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler@5c0e8bb9
[http-nio-80-exec-1] 2024-01-18 10:43:54,758 DEBUG o.s.w.s.DispatcherServlet - Completed 404 NOT_FOUND
[http-nio-80-exec-2] 2024-01-18 10:44:00,495 DEBUG o.s.w.s.DispatcherServlet - GET "/restful/request", parameters={}
[http-nio-80-exec-2] 2024-01-18 10:44:00,502 DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to public java.lang.String com.imooc.restful.controller.RestfulController.doGetRequest()
http://localhost/restful/request-准备执行
[http-nio-80-exec-2] 2024-01-18 10:44:00,539 DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Using 'application/json;charset=utf-8', given [application/json, text/javascript, */*;q=0.01] and supported [text/html;charset=utf-8, application/json;charset=utf-8, text/plain, */*, application/json, application/*+json]
[http-nio-80-exec-2] 2024-01-18 10:44:00,539 DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Writing ["{"message":"返回查询结果"}"]
http://localhost/restful/request-目标处理成功
http://localhost/restful/request-响应内容已产生
[http-nio-80-exec-2] 2024-01-18 10:44:00,580 DEBUG o.s.w.s.DispatcherServlet - Completed 200 OK
[http-nio-80-exec-5] 2024-01-18 10:44:08,194 DEBUG o.s.w.s.DispatcherServlet - GET "/restful/persons", parameters={}
[http-nio-80-exec-5] 2024-01-18 10:44:08,195 DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to public java.util.List<com.imooc.restful.entity.Person> com.imooc.restful.controller.RestfulController.findPersons()
http://localhost/restful/persons-准备执行
RestfulController.findPersons() - return list
[http-nio-80-exec-5] 2024-01-18 10:44:08,211 DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Using 'application/json', given [application/json, text/javascript, */*;q=0.01] and supported [application/json, application/*+json]
[http-nio-80-exec-5] 2024-01-18 10:44:08,211 DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Writing [[com.imooc.restful.entity.Person@619c4d80, com.imooc.restful.entity.Person@71459fb]]
http://localhost/restful/persons-目标处理成功
http://localhost/restful/persons-响应内容已产生
===================================================================
D:\logs\history.2024-01-18
[http-nio-80-exec-1] 2024-01-18 10:43:54,755 INFO c.i.r.i.AccessHistoryInterceptor - 0:0:0:0:0:0:0:1|http://localhost/login.html|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
[http-nio-80-exec-2] 2024-01-18 10:44:00,502 INFO c.i.r.i.AccessHistoryInterceptor - 0:0:0:0:0:0:0:1|http://localhost/restful/request|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
[http-nio-80-exec-5] 2024-01-18 10:44:08,195 INFO c.i.r.i.AccessHistoryInterceptor - 0:0:0:0:0:0:0:1|http://localhost/restful/persons|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
[http-nio-80-exec-3] 2024-01-18 10:44:10,137 INFO c.i.r.i.AccessHistoryInterceptor - 0:0:0:0:0:0:0:1|http://localhost/restful/request/100|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
[http-nio-80-exec-4] 2024-01-18 10:44:10,935 INFO c.i.r.i.AccessHistoryInterceptor - 0:0:0:0:0:0:0:1|http://localhost/restful/request|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
[http-nio-80-exec-6] 2024-01-18 10:44:11,481 INFO c.i.r.i.AccessHistoryInterceptor - 0:0:0:0:0:0:0:1|http://localhost/restful/request|Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
applicationContext.xml
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/resources/**"/>
<bean class="com.imooc.restful.interceptor.AccessHistoryInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>